/*
 * @(#)InterceptorFactory.java 1.0 2009/12/01
 */
package stardust.core.java.interceptor;


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import stardust.Stardust;
import stardust.core.java.compiler.AbstractClassBuilder;
import stardust.core.java.compiler.ClassBuilderFactory;
import stardust.core.java.reflect.TypeUtils;
import stardust.core.log.Log;
import stardust.core.support.Sequence;
import stardust.core.support.cache.Cache;


/**
 * 代理工厂类，提供可缓存的拦截器工厂。
 * <p>
 * 每个需要代理的类只会被编译成模板一次，后续使用时通过在构造器中传递相关参数可实现重复缓存代理。
 * <p/>
 * @version 1.0, 2009/12/01
 * @author ChenChang
 */
public class InterceptorFactory
{

  public static final String EXT = Stardust.SIGNATURE + "AUTO_CLASS";

  public static final String PACKAGE = Stardust.SIGNATURE + "AUTO_PACKAGE";

  /**
   * 日志记录器。
   */
  private static Log log = new Log(InterceptorFactory.class);
  
  /**
   * 后缀序列生成器。
   */
  private static final Sequence sequence = new Sequence();

  /**
   * 类拦截器模板的缓存。
   */
  private Cache<Class<?>, Class<?>> classCache;
  
  /**
   * 拦截器代码生成模板。
   */
  private InterceptorTemplateCallback templateCallback;
  
  /**
   * 源代码编译器。
   */
  private AbstractClassBuilder builder;

  /**
   * 获取一个拦截器工厂的实例。
   */
  private InterceptorFactory()
  {
    if (classCache == null)
    {
      classCache = new Cache<Class<?>, Class<?>>();
    }

    this.builder = ClassBuilderFactory.createClassBuilder();

    // 程序运行结束时删除临时目录
    this.builder.deleteOnExit();
  }

  /**
   * 为类中的所有方法创建拦截。
   */
  public <T> T create(T instance, Interceptor interceptor)
  {
    return this.create(instance, interceptor, instance.getClass().getMethods());
  }

  /**
   * 为参数中接口或类定义的方法创建拦截。
   */
  public <T> T create(T instance, Interceptor interceptor, Class<?>... interceptClass)
  {
    Set<Method> methods = new HashSet<Method>();

    for (int i = 0; i < interceptClass.length; i++)
    {
      Collections.addAll(methods, interceptClass[i].getMethods());
    }

    return this.create(instance, interceptor, methods.toArray(new Method[methods.size()]));
  }

  /**
   * 为参数中接口或类定义的方法创建拦截。
   */
  public <T> T create(T instance, Interceptor interceptor, Method... method)
  {
    Class<?> interceptorClass = instance.getClass();
    Class<?> sourceClass;

    while (TypeUtils.testCastToType(interceptorClass, InterceptorIdentity.class))
    {
      interceptorClass = interceptorClass.getSuperclass();
    }

    sourceClass = interceptorClass;

    try
    {
      interceptorClass = this.getProxyClass(interceptorClass);
      
      return (T) (interceptorClass.getConstructor(sourceClass, Interceptor.class, Method[].class).newInstance(instance, interceptor, method));
    }
    catch(Exception e)
    {
      throw new InterceptorException(e);
    }
  }
  
  /**
   * 从缓存中获取代理类类型，如果不存在将返回<tt>null</tt>值。
   */
  public Class<?> getProxyClassCache(Class<?> sourceClass)
  {
    // 尝试从缓存中取 Class 对象。
    Class<?> cacheClass;

    if ((cacheClass = classCache.get(sourceClass)) != null)
    {
      return cacheClass;
    }
    
    return null;
  }

  /**
   * 编译或从缓存中创造一个代理类。
   * @throws NoSuchMethodException 
   * @throws InvocationTargetException 
   * @throws IllegalAccessException 
   * @throws InstantiationException 
   * @throws SecurityException 
   * @throws IllegalArgumentException 
   */
  public synchronized Class<?> getProxyClass(Class<?> sourceClass) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
  {
    // 尝试从缓存中取 Class 对象。
    Class<?> cacheClass;

    if ((cacheClass = this.getProxyClassCache(sourceClass)) != null)
    {
      return cacheClass;
    }
    else
    {
      List<Class<?>> sourceClasses = new ArrayList<Class<?>>();

      sourceClasses.add(sourceClass);
      this.createClasses(sourceClasses);

      return classCache.get(sourceClass);
    }
  }

  /**
   * 编译或从缓存中创造一个代理类集合。
   * @throws NoSuchMethodException 
   * @throws InvocationTargetException 
   * @throws IllegalAccessException 
   * @throws InstantiationException 
   * @throws SecurityException 
   * @throws IllegalArgumentException 
   */
  public synchronized void createClasses(List<Class<?>> sourceClasses) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
  {
    Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
    String buildClassName;
    Class<?> sourceClass;

    for (int i = 0; i < sourceClasses.size(); i++)
    {
      // 尝试从缓存中取 Class 对象。
      Class<?> cacheClass = classCache.get(sourceClasses.get(i));

      if (cacheClass != null)
      {
        continue;
      }

      String className = sourceClasses.get(i).getSimpleName() + InterceptorFactory.EXT + InterceptorFactory.sequence.next();
      InterceptorTemplate template;
      
      template = new InterceptorTemplate(InterceptorFactory.PACKAGE, className, sourceClasses.get(i), this.templateCallback);

      this.builder.add(template.getClassName(), template.getCode());
      classes.put(template.getClassName(), sourceClasses.get(i));
    }

    if (builder.compile())
    {
      Iterator<String> names = classes.keySet().iterator();

      while (names.hasNext())
      {
        buildClassName = names.next();
        sourceClass = classes.get(buildClassName);
        Class<?> buildClass = null;

        try
        {
          buildClass = this.builder.getClassLoader().loadClass(buildClassName);
          classCache.put(sourceClass, buildClass);

          log.trace("加载代理类：", buildClass.getName(), "[", sourceClass.getName(), "]。");
        }
        catch(InterceptorException e)
        {
          throw e;
        }
        catch(ClassNotFoundException e)
        {
          if (buildClass != null)
          {
            throw new InterceptorException("创建代理类成功，但无法加载类：" + buildClass.getName() + "[" + sourceClass.getName() + "]。", e);
          }
          else
          {
            throw new InterceptorException("创建代理类成功，但无法加载类：" + buildClass + "[" + sourceClass.getName() + "]。", e);
          }
        }
      }
    }
    else
    {
      throw new InterceptorException("创建代理类失败。");
    }
  }
  
  public InterceptorTemplateCallback getTemplateCallback()
  {
    return templateCallback;
  }

  public void setTemplateCallback(InterceptorTemplateCallback templateCallback)
  {
    this.templateCallback = templateCallback;
  }

  /**
   * 获取拦截器工厂实例，这是一个单例模式。
   */
  public static InterceptorFactory createInstance()
  {
    return new InterceptorFactory();
  }

  public static void main(String[] args) throws Throwable
  {
    InterceptorFactory factory = InterceptorFactory.createInstance();

    Object o;

    o =
    factory.create(new Object(), new Interceptor()
    {

      public Object invoke(InterceptorProcessor processor) throws Throwable
      {
        Object returnValue;

        System.out.println("进入AOP方法111...begin");
        returnValue = processor.process();
        System.out.println("进入AOP方法111...end");
        return returnValue;
      }

    });
    
    System.out.println(o.getClass());

    o.toString();
  }

}
